/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_Studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#pragma once


#include <基本类型.h>
#include <JIT.h>
#include <basic_vec.h>
#include <引擎枚举数据.h>
#include <引擎数据类型.h>


enum E_节点更新方式 {
	e_节点更新_关闭 = 1 << 0,
	e_节点更新_被动 = 1 << 1,
	e_节点更新_逐帧 = 1 << 2,
	e_节点更新_实时 = 1 << 3,
	e_节点更新_离线 = 1 << 4,
	e_节点更新_手动 = 1 << 5,
};

enum E_插座方向 {
	e_插座Type_输入,
	e_插座Type_输出,
};

enum E_节点执行 {
	e_节点执行_传递,
	e_节点执行_中断,
};

//enum E_变换操作类型 {
//	e_变换操作_移动,
//	e_变换操作_旋转,
//	e_变换操作_缩放,
//};


class C_插座基类;
class C_节点基类;
class S_Scene;


struct S_插座创建参数 {
	E_值类型		m_类型;
	std::u16string	m_name;
	bool			m_多输入;
};

typedef bool(*f_plugin_节点)(class C_节点基类* 节点);
typedef E_节点执行(*f_plugin_节点更新)(class C_节点基类* 节点);
typedef bool(*f_plugin_节点复制)(C_节点基类* 目标节点, const class C_节点基类* 源节点);
typedef const uint8* (*f_plugin_节点加载)(C_节点基类* 目标节点, const uint8* data_ptr);
typedef bool(*f_plugin_节点保存)(C_节点基类* 目标节点, S_UI8Array* 块);

//typedef bool(*f_plugin_节点更新)(class C_节点基类& 节点);
typedef bool(*fn_plugin_物体创建销毁)(std::vector<S_物体*>& 新物体, bool 立即);
typedef bool(*fn_plugin_选择物体变换)(std::vector<S_物体*>& 新物体);
typedef bool(*fn_plugin_物体选择更新)(const std::vector<S_物体*>& 选择物体);

typedef bool(*fn_plugin_变换操作)(E_变换 type);
typedef bool(*fn_plugin_移动变换操作)(S_物体* ob, vec3 开始位置, vec3 当前位置, E_轴向 轴向);
typedef bool(*fn_plugin_旋转变换操作)(S_物体* ob, float32 开始弧度, float32 当前弧度, E_轴向 轴向);
typedef bool(*fn_plugin_缩放变换操作)(S_物体* ob, float32 缩放, E_轴向 轴向);

typedef bool(*f_plugin_场景更新)(S_Scene* 场景);

typedef const uint8* (*expand_插座数据加载)(C_插座基类* socket, S_结构指针 value, const uint8* 下一次读取数据指针);
typedef bool(*expand_插座数据保存)(C_插座基类* socket, S_结构指针 value, S_UI8Array* data);

typedef struct {
	uint64 m_字节大小;
	expand_插座数据加载 mf_加载;
	expand_插座数据保存 mf_保存;
}S_自定义结构插座数据;



typedef struct {
	f_plugin_节点 mf_创建;
	f_plugin_节点 mf_销毁;

	f_plugin_节点更新 mf_更新;
	f_plugin_节点复制 mf_复制;

	f_plugin_节点保存 mf_保存;
	f_plugin_节点加载 mf_加载;

}S_节点构建参数;

typedef struct {
	fn_plugin_物体创建销毁 mf_物体创建;
	fn_plugin_物体创建销毁 mf_物体销毁;
	//选择的物体在视口变换操作时 回调
	fn_plugin_选择物体变换 mf_选择物体变换;
	fn_plugin_物体选择更新 mf_物体选择;
	fn_plugin_物体选择更新 mf_物体更新;

	bool m_拾取;
	bool m_渲染;
	bool m_可操作;
}S_物体构建插件构建参数;

typedef struct {
	fn_plugin_变换操作		mf_开始;
	fn_plugin_移动变换操作	mf_移动;
	fn_plugin_旋转变换操作	mf_旋转;
	fn_plugin_缩放变换操作	mf_缩放;
	fn_plugin_变换操作		mf_完成;
}S_变换操作插件构建参数;

typedef struct {
	f_plugin_场景更新 mf_场景更新后;
	f_plugin_场景更新 mf_场景渲染前;
}S_场景插件构建参数;

enum class E_平面方向 : uint8 {
	e_XZ,
	e_XY,
	e_YZ,
};
typedef const void (*expand_3D视口移动回调)(C_Widget* self, vec3 游标位置, vec2 鼠标窗口位置);
typedef const bool (*expand_3D视口开始回调)(C_Widget* self, vec2 鼠标窗口位置, E_平面方向& 平面);
typedef const void (*expand_3D视口结束回调)(C_Widget* self, vec3 游标位置, vec2 鼠标窗口位置);
typedef struct {
	expand_3D视口移动回调	mf_鼠标移动;
	expand_3D视口开始回调	mf_鼠标开始;
	expand_3D视口结束回调	mf_鼠标结束;
	E_鼠标按钮				m_鼠标按键;
	bool					m_放开确认;
	//uint32					m_平面;
}S_3D视口操作回调;


Inline S_节点构建参数* f_nodePlugin_节点构建参数(S_插件模块& 插件模块) {
	return (S_节点构建参数*)(插件模块.m_Object);
}

Inline S_物体构建插件构建参数* f_nodePlugin_物体构建参数(S_插件模块& 插件模块) {
	return (S_物体构建插件构建参数*)(插件模块.m_Object);
}

Inline S_变换操作插件构建参数* f_nodePlugin_变换操作构建参数(S_插件模块& 插件模块) {
	return (S_变换操作插件构建参数*)(插件模块.m_Object);
}

Inline S_场景插件构建参数* f_nodePlugin_场景插件构建参数(S_插件模块& 插件模块) {
	return (S_场景插件构建参数*)(插件模块.m_Object);
}


Inline void f_节点插件_销毁节点模块构建参数(S_插件模块& 模块) {
	free(模块.m_Object);
}

//extern "C" {

API_EXPORT S_设备环境&	f_nodePlugin_get3D设备环境();

API_EXPORT S_插件模块	f_nodePlugin_构建模块(const std::u16string& name, E_扩展类型 扩展类型, E_工作区类型 工作区 = E_工作区类型::e_节点视口);

API_EXPORT void f_nodePlugin_设置节点属性(C_节点基类* node, const std::u16string& name, E_节点更新方式 更新方式, const std::u16string& ico);

API_EXPORT void f_nodePlugin_创建插座(C_节点基类* node, E_插座方向 方向, const std::vector<S_插座创建参数>& 插座参数);
API_EXPORT void f_nodePlugin_销毁插座(C_节点基类* node);

API_EXPORT void		f_node_扩展节点添加物体(C_节点基类* n, const std::vector<S_物体*>& ob, bool 追加 = false);
API_EXPORT void		f_node_扩展节点添加属性(C_节点基类* n, const std::vector<S_Props>& prop, bool 追加 = false);

API_EXPORT std::vector<S_物体*>& f_node_get扩展节点物体(C_节点基类* n);
API_EXPORT std::vector<S_Props>& f_node_get扩展节点属性(C_节点基类* n);



//======================================== 插座数据 ==================================================
API_EXPORT void f_nodePlugin_setSocketData(C_节点基类* node, E_插座方向 方向, uint32 loc, void* data);
API_EXPORT void* f_nodePlugin_getSocketData(C_节点基类* node, E_插座方向 方向, uint32 loc, uint32 接入ID);
API_EXPORT S_设备环境& f_nodePlugin_get设备环境(C_节点基类* node);

uint32 f_nodePlugin_get插座连接数量(C_节点基类* node, E_插座方向 方向, uint32 loc);


API_EXPORT bool f_nodePlugin_插座类型检查(C_节点基类* node, E_插座方向 方向, uint32 loc, E_值类型 值类型);

//}

template<typename T>
T* f_nodePlugin_get插座数据(C_节点基类* node, E_插座方向 方向, uint32 loc, uint32 接入ID) {
	return (T*)f_nodePlugin_getSocketData(node, 方向, loc, 接入ID);
}

#ifdef _DEBUG
#define DEF_插座类型检查(值类型) assert( f_nodePlugin_插座类型检查(node, 方向, loc, 值类型) );
#else
#define DEF_插座类型检查(值类型)
#endif // DEBUG


Inline float32* f_nodePlugin_getF32插座数据(C_节点基类* node, E_插座方向 方向, uint32 loc, uint32 接入ID = 0) {
	DEF_插座类型检查(E_值类型::e_Type_F32);
	return f_nodePlugin_get插座数据<float32>(node, 方向, loc, 接入ID);
}

Inline int32* f_nodePlugin_getI32插座数据(C_节点基类* node, E_插座方向 方向, uint32 loc, uint32 接入ID = 0) {
	DEF_插座类型检查(E_值类型::e_Type_I32);
	return f_nodePlugin_get插座数据<int32>(node, 方向, loc, 接入ID);
}

Inline uint32* f_nodePlugin_getUI32插座数据(C_节点基类* node, E_插座方向 方向, uint32 loc, uint32 接入ID = 0) {
	DEF_插座类型检查(E_值类型::e_Type_UI32);
	return f_nodePlugin_get插座数据<uint32>(node, 方向, loc, 接入ID);
}

Inline bool* f_nodePlugin_getBool插座数据(C_节点基类* node, E_插座方向 方向, uint32 loc, uint32 接入ID = 0) {
	DEF_插座类型检查(E_值类型::e_Type_Bool);
	return f_nodePlugin_get插座数据<bool>(node, 方向, loc, 接入ID);
}

Inline S_物体* f_nodePlugin_getOB插座数据(C_节点基类* node, E_插座方向 方向, uint32 loc, uint32 接入ID = 0) {
	DEF_插座类型检查(E_值类型::e_Type_Object);
	return f_nodePlugin_get插座数据<S_物体>(node, 方向, loc, 接入ID);
}

Inline S_自定义结构插座数据* f_nodePlugin_get自定义结构插座数据(C_节点基类* node, E_插座方向 方向, uint32 loc, uint32 接入ID = 0) {
	DEF_插座类型检查(E_值类型::e_Type_自定义结构);
	return f_nodePlugin_get插座数据<S_自定义结构插座数据>(node, 方向, loc, 接入ID);
}



Inline S_F32Array* f_nodePlugin_getF32Array插座数据(C_节点基类* node, E_插座方向 方向, uint32 loc, uint32 接入ID = 0) {
	DEF_插座类型检查(E_值类型::e_Type_F32_1D)
	return f_nodePlugin_get插座数据<S_F32Array>(node, 方向, loc, 接入ID);
}

Inline S_I32Array* f_nodePlugin_getI32Array插座数据(C_节点基类* node, E_插座方向 方向, uint32 loc, uint32 接入ID = 0) {
	DEF_插座类型检查(E_值类型::e_Type_I32_1D)
	return f_nodePlugin_get插座数据<S_I32Array>(node, 方向, loc, 接入ID);
}

Inline S_UI32Array* f_nodePlugin_getUI32Array插座数据(C_节点基类* node, E_插座方向 方向, uint32 loc, uint32 接入ID = 0) {
	DEF_插座类型检查(E_值类型::e_Type_UI32_1D)
	return f_nodePlugin_get插座数据<S_UI32Array>(node, 方向, loc, 接入ID);
}

Inline S_Vec2Array* f_nodePlugin_getVec2Array插座数据(C_节点基类* node, E_插座方向 方向, uint32 loc, uint32 接入ID = 0) {
	DEF_插座类型检查(E_值类型::e_Type_Vec2_1D)
		return f_nodePlugin_get插座数据<S_Vec2Array>(node, 方向, loc, 接入ID);
}

Inline S_Vec3Array* f_nodePlugin_getVec3Array插座数据(C_节点基类* node, E_插座方向 方向, uint32 loc, uint32 接入ID = 0) {
	DEF_插座类型检查(E_值类型::e_Type_Vec3_1D)
		return f_nodePlugin_get插座数据<S_Vec3Array>(node, 方向, loc, 接入ID);
}

Inline S_OBArray* f_nodePlugin_getOBArray插座数据(C_节点基类* node, E_插座方向 方向, uint32 loc, uint32 接入ID = 0) {
	DEF_插座类型检查(E_值类型::e_Type_Object_1D)
	return f_nodePlugin_get插座数据<S_OBArray>(node, 方向, loc, 接入ID);
}







//===================================== 物体操作 ==========================================

//enum class E_预设网格 {
//	e_面,
//	e_线段,
//	e_点,
//};

/*
E_物体类型::t_网格物体
E_物体类型::t_虚拟体 默认带一个网格对象
*/
API_EXPORT S_物体*	f_nodePlugin_创建物体(S_设备环境& ctx, E_物体类型 类型);
API_EXPORT void		f_nodePlugin_销毁物体(S_物体* ob);

API_EXPORT S_Mesh*	f_nodePlugin_物体添加网格(S_物体* ob, E_网格类型 类型);

//API_EXPORT S_Mesh* f_nodePlugin_创建预设网格(E_预设网格 预设);
API_EXPORT S_物体*				f_nodePlugin_get激活物体();



//===================================== 网格操作 ==========================================




//===================================== 材质操作 ==========================================

enum class E_预设材质 {
	e_基本面光照,
	e_线段,
	e_点,
};

API_EXPORT S_着色线管*	f_nodePlugin_创建线管(const S_着色器创建配置& 线管创建配置);
API_EXPORT void			f_nodePlugin_销毁线管(S_着色线管* 线管);

API_EXPORT S_材质管线*	f_nodePlugin_创建材质();
API_EXPORT void		f_nodePlugin_销毁材质(S_材质管线* 材质);


API_EXPORT S_材质管线* f_nodePlugin_get预设材质(E_预设材质 预设);





//void	f_nodePlugin_物体销毁网格(S_物体* ob);
//void	f_nodePlugin_物体添加到场景(S_物体* ob);
//void	f_nodePlugin_物体从场景移除(S_物体* ob);





